/*
 * Copyright (C) 2012 CNL - ECE Dept - National University of Singapore
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package sg.nus.ece.cnl.veracity.execution;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.io.InputStream;
import org.apache.log4j.Logger;
import sg.nus.ece.cnl.veracity.access.SshUserCredentials;
import sg.nus.ece.cnl.veracity.access.TargetServer;

/**
 * Execute a command on remote host given the login to this host. It uses ssh
 * approach in the Jsch library.
 *
 * @author tram
 */
public class RemoteCommandExecutor {

    private static final Logger log = Logger.getLogger(RemoteCommandExecutor.class);
    // remote command executor instance
    private static RemoteCommandExecutor instance;

    private RemoteCommandExecutor() {
    }

    public static RemoteCommandExecutor getInstance() {

        if (instance == null) {
            instance = new RemoteCommandExecutor();
        }

        return instance;
    }
    
    /**
     * Execute a command on remote host
     * @param remoteServer remote server
     * @param userCredentials user credential used for the connection
     * @param command command to be executed
     * @return exit code of the command
     */
    public int exec(TargetServer remoteServer, SshUserCredentials userCredentials, String command) {

        int exitCode = -1;

        try {
            Session session = (new JSch()).getSession(userCredentials.getLogin(), remoteServer.getHostname(), 22);


            session.setUserInfo(userCredentials);
            session.connect();

            Channel channel = session.openChannel("exec");
            ((ChannelExec) channel).setCommand(command);
            
            channel.setInputStream(null);

            ((ChannelExec) channel).setErrStream(System.err);

            InputStream in = channel.getInputStream();

            channel.connect();

            byte[] tmp = new byte[1024];
            while (true) {
                while (in.available() > 0) {
                    int i = in.read(tmp, 0, 1024);
                    if (i < 0) {
                        break;
                    }
                   System.out.print(new String(tmp, 0, i));
                }
                if (channel.isClosed()) {
                    exitCode = channel.getExitStatus();
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (java.lang.InterruptedException ex) {
                    log.error("Thread interrupted: " + ex.getMessage());
                }
            }
            channel.disconnect();
            session.disconnect();
        } catch (java.io.IOException ex) {
            log.error("Cannot execute remote command: " + ex.getMessage()); 
        } catch (com.jcraft.jsch.JSchException ex) {
            log.error("Cannot execute remote command: " + ex.getMessage()); 
        }
        return exitCode;
    }
}
